﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Adp.Pleiade.Fwk.Entity;
using Adp.Pleiade.Fwk.Referentiels.Data;
using Adp.Pleiade.Fwk.Referentiels.EntitesReferentielMultiple;
using System.Collections;
using System.Threading.Tasks;
using Adp.Pleiade.Fwk.Service.WCF;
using Adp.Pleiade.Fwk.Calcul.UI;
using Adp.Pleiade.Fwk.Common.Logs;
using System.IO;

namespace OutillageTests
{    
    public class ClassParser
    {
        private Type classToParse;
        private Dictionary<MethodInfo, bool> cartography;
        private StreamWriter log;

        /// <summary>
        /// Constructeur
        /// </summary>
        /// <param name="aClass"></param>
        public ClassParser(Type aClass)
        {
            classToParse = aClass;
            cartography = new Dictionary<MethodInfo, bool>();
            log = new StreamWriter(@"C:\Generation TU\ParserLog.txt");            
        }

        public Dictionary<MethodInfo, bool> ParseClass()
        {
            // Récupération des MethodInfo, exclusion des interfaces
            if (!classToParse.IsInterface)
            {
                MethodInfo[] methodArray = classToParse.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

                Parallel.ForEach(methodArray, method => { ParseMethod(method); });

                //foreach (var method in methodArray)
                //{
                //    ParseMethod(method);
                //}
            }

            log.Close();
            return cartography;
        }

        public void ParseMethod(string methodName)
        {
            // Exclusion des get_ et set_
            if (!methodName.ToUpper().Contains("GET_") &&
                !methodName.ToUpper().Contains("SET_"))
                ParseMethod(classToParse.GetMethod(methodName));
        }

        public void ParseMethod(MethodInfo method)
        {
            try
            {
                bool testable = true;

                // Contrôle sur le type de retour
                testable = ReturnTypeCheck(method);
                
                // Si pas d'exception non désirée dans le code, contrôle des paramètres
                if (testable)
                {
                    // Exclusion des get_ et set_
                    if (!method.Name.ToUpper().Contains("GET_") &&
                        !method.Name.ToUpper().Contains("SET_"))
                    {
                        foreach (ParameterInfo parameter in method.GetParameters())
                        {
                            testable = ParameterTypeCheck(parameter);
                            if (!testable) break;
                        };
                    }
                    else
                        testable = false;
                }

                // Si tous les paramètres sont OK, contrôle des variables locales
                if (testable && method.GetMethodBody() != null)
                {
                    foreach (LocalVariableInfo variable in method.GetMethodBody().LocalVariables)
                    {
                        testable = LocalVariableTypeCheck(variable);
                        if (!testable) break;
                    }
                }

                cartography.Add(method, testable);
            }
            catch 
            {
                lock (this)
                {
                    log.WriteLine(DateTime.Now.ToString() + " : Méthode non traitée : " + method.Name +
                        " - Classe " + classToParse.Name);
                }
            }
        }

        private static bool LocalVariableTypeCheck(LocalVariableInfo variablesLocale)
        {
            return Tools.CheckForUnrecognizedType(variablesLocale.LocalType);
        }

        private static bool ParameterTypeCheck(ParameterInfo parametre)
        {
            return Tools.CheckForUnrecognizedType(parametre.ParameterType);
        }

        private static bool ReturnTypeCheck(MethodInfo method)
        {
            return Tools.CheckForUnrecognizedType(method.ReturnType);
        }
    }
}
